package cn.dogger.easyboot.netty.chat;

import cn.dogger.easyboot.netty.handler.NettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

import java.util.Scanner;

/**
 * @author dogger
 * 2022/11/25 18:05
 */
public class NettyServer {

    public static void main(String[] args) {
        //线程组bossGroup处理连接请求,含有的子线程数为cpu核心数两倍
        EventLoopGroup bossGroup = new NioEventLoopGroup(10);
        //线程组workerGroup处理与客户端的业务来往
        EventLoopGroup workerGroup = new NioEventLoopGroup(10);

        //创建服务端启动对象
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //设置参数
        serverBootstrap
                //设置两个线程组
                .group(bossGroup, workerGroup)
                //使用NioServerSocketChannel作为服务端通道实现
                .channel(NioServerSocketChannel.class)
                //初始化服务端连接队列大小,一时间只能处理一客户端连接;并发走队列等待
                .option(ChannelOption.SO_BACKLOG, 1024)
                //创建通道并初始化对象,设置初始化参数
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) {
                        ChannelPipeline pipeline = channel.pipeline();
                        //注意! 自定义的SocketChannel设置处理类最好放最后面,因为这玩意儿是从上往下读取的,如果放最上面,会因为没读取到http编解码器而报错
                        pipeline
                                /*========================以下是用于支持http协议,(NettyClient连接需注释掉)====================*/
                                // HTTP请求编解码器
                                .addFirst(new HttpServerCodec())
                                // 文件分块传输,对写大数据流的支持
                                .addFirst(new ChunkedWriteHandler())
                                // HTTP聚合器
                                .addLast(new HttpObjectAggregator(1024 * 1024 * 5))
                                /*========================以上是用于支持http协议,(NettyClient连接需注释掉)====================*/
                                /*
                                 * websocket 服务器处理的协议，用于指定给客户端连接访问的路由,例如:  ws://localhost:8080/wss
                                 * 本handler会帮你处理一些繁重的复杂的事
                                 * 会帮你处理握手动作：handshaking（close，ping，pong） ping + pong = 心跳
                                 * 对呀websocket来讲，都是以frames进行传输的，不同的数据类型对应的frames也不同
                                 */
                                .addLast(new WebSocketServerProtocolHandler("/wss"))
                                 //post请求方式
                                 //.addLast(new HttpObjectAggregator(65536))
                                /*如果是前端发送的,需注释掉以下*/
                                 //加入解码器
                                 //.addLast("decoder", new StringDecoder())
                                 //加入编码器
                                //.addLast("encoder", new StringEncoder())
                                /*如果是前端发送的,需注释掉以上*/
                                //对workerGroup的SocketChannel设置处理类
                                .addLast(new NettyServerHandler())
                        ;
                    }
                });
        System.out.println("netty 服务端启动..." + "\n");
        try {
            ChannelFuture channelFuture = serverBootstrap.bind(8989).sync();
            Channel channel = channelFuture.channel();
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()) {
                String msg = scanner.nextLine();
                channel.writeAndFlush(msg);
            }
            //关闭通道
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
